package com.wngbms.netty.seatdemo.message;

import com.wngbms.netty.seatdemo.comm.*;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.UUID;

@Slf4j
public class SeatInMessage {

    private ChannelHandlerContext channelHandlerContext;

    // 消息头
    private BaseHeader baseHeader;
    // 消息体字节数
    private int bodyLength;
    // 包括消息头在内的总字节数
    private int totalLength;
    // 已接收字节数
    private int receivedLength;
    // 可写入的消息体数组索引下标
    private int writableIndex;
    // 消息体
    private byte[] body;
    File file;
    FileOutputStream fileOutputStream;
    FileChannel fileOutChannel;

    public BaseHeader getBaseHeader() {
        return baseHeader;
    }

    public byte[] getBody() {
        return body;
    }

    public ChannelHandlerContext getChannelHandlerContext() {
        return channelHandlerContext;
    }

    public File getFile() {
        return file;
    }

    public void setChannelHandlerContext(ChannelHandlerContext channelHandlerContext) {
        this.channelHandlerContext = channelHandlerContext;
    }

    public void checkHeader() {
        if (baseHeader.isFinish()) {
            MagicVersion magicVersion = baseHeader.getMagicVersion();
            CmdType cmdType = baseHeader.getCmdType();
            BodyType bodyType = baseHeader.getBodyType();
            EncryptionType encryptionType = baseHeader.getEncryptionType();
            ReqOrResp reqOrResp = baseHeader.getReqOrResp();
            int bodyLength = baseHeader.getBodyLength();

            log.debug("请求头信息:{}, magicVersion:{}, cmdType:{}, bodyType:{}, encryptionType:{}, reqOrResp:{}, bodyLength:{}",
                    baseHeader.toString(), magicVersion, cmdType, bodyType, encryptionType, reqOrResp, bodyLength);

            if (magicVersion == null | cmdType == null
                    | bodyType == null | encryptionType == null
                    | reqOrResp == null | bodyLength < 0) {
                throw new IllegalStateException("请求头不合法" + Arrays.asList(baseHeader));
            }
        }
    }

    public void setBaseHeader(BaseHeader baseHeader) throws IOException {
        this.baseHeader = baseHeader;

        if (!baseHeader.isFinish()) {
            return;
        }
// 校验请求头是否合法
        checkHeader();

        this.bodyLength = baseHeader.getBodyLength();
        final int headerLength = BaseHeader.HEADER_LENGTH;
        this.totalLength = headerLength + this.bodyLength;
        this.receivedLength = headerLength;

        if (baseHeader.getCmdType() != CmdType.BINARY_TEST_UPLOAD) {
            this.body = new byte[bodyLength];
        } else {
            String userDir = System.getProperty("user.dir");
            String fileName = UUID.randomUUID().toString();
            String fileFullPathName = userDir + File.separator + fileName + "-server";

            file = new File(fileFullPathName);
            if (!file.exists()) {
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            this.fileOutChannel = fileOutputStream.getChannel();
        }
    }

    public boolean finished() throws IOException {
        boolean b = receivedLength == totalLength && baseHeader.isFinish();
        if ((baseHeader.getCmdType() == CmdType.BINARY_TEST_UPLOAD) && b) {
            fileOutChannel.close();
            fileOutputStream.close();
        }
        return b;
    }

    public void writeBody(ByteBuf byteBuf, int readableBytes) throws IOException {
        if (baseHeader.getCmdType() != CmdType.BINARY_TEST_UPLOAD) {
            int min = Math.min(readableBytes, this.bodyLength - writableIndex);
            byteBuf.readBytes(this.body, writableIndex, min);
            writableIndex += min;
            receivedLength += min;
        } else {
            byteBuf.readBytes(fileOutChannel, receivedLength - BaseHeader.HEADER_LENGTH, readableBytes);
//            byteBuf.readBytes(fileOutChannel, 0, bodyLength);

            receivedLength += readableBytes;
            log.info("已接收文件大小:{}, 文件总大小:{}", receivedLength - BaseHeader.HEADER_LENGTH, bodyLength);
        }
    }

}
